package javafx179labs.nez.hr.dao.db;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javafx179labs.nez.hr.bean.refactor.Entity;
import javafx179labs.nez.hr.exception.IncorrectModelException;

/**
 *
 * @author SSheypak
 */


public class HRDaoDBImpl<T extends Entity>{
    private static final String FIELDS_MAPPING_METH = "getFieldMapping";
    private static final String PERSISTENT_STORAGE_NAME = "getPersistentStorageName";

    private Map<Integer, String> fieldMapping = null;   //map with pairs: key->fieldName
    private List<String> fieldNames = null;             //List contains entity filed names
    private String tableName = null;                    //DB table

    private T instance; //plain instance of bean

    public HRDaoDBImpl(T entity) throws Exception{
        instance = entity;
        setFieldNamesAndMapping();
    }

    /**Generic method for getting Entity subclasses from DB
     * @param entityInstance is an instance of an entity type you want to get.
     * @return list of entites
     */
    public <T> List<T> getEntities() throws Exception{
        List<T> result = new ArrayList<T>();
        String query = buildSelectQuery();
        //TODO: get connection and map results to java beans
        result = executeSelectQuery(query);
        
        return result;
    }

    /**Executes query and maps result to bean fields
     *@param query is a SQL query.
     **/
    private <T> List<T> executeSelectQuery(String query) throws Exception{
        throw new IncorrectModelException("Implement me, plz!");
    }

    protected void setFieldNamesAndMapping() throws IncorrectModelException{
        try{
            Method fieldsMappingMeth = findMethod(instance.getClass(), FIELDS_MAPPING_METH);
            
            fieldMapping = (Map<Integer, String>)fieldsMappingMeth.invoke(instance, new Object[]{});
            
            fieldNames = new ArrayList(fieldMapping.values());  //wrap some Collection to List implementation
            Collections.sort(fieldNames);   //order alphabetically

            Method tableNameMeth = findMethod(instance.getClass(), PERSISTENT_STORAGE_NAME);
            tableName =  (String)tableNameMeth.invoke(instance, new Object[]{});
        }catch(Exception e){
            e.printStackTrace();
            throw new IncorrectModelException(e.getMessage());
        }
    }

    /**Tries to find method in class and its superclasses
     * @param clz is Class where method should be.
     * @param methodName is a name of a method. The method doesn't accept any params
     */
    protected Method findMethod(Class clz, String methodName) throws IncorrectModelException{
        if (clz.isInstance(new Object())){  //This is exit from recursive method call
            //TODO: log it as error and then throw
            throw new IncorrectModelException("This class["+clz.getName()+"] doesn't have method ["+methodName+"]");
        }
        Method m = null;
        try {
            m = clz.getDeclaredMethod(methodName, new Class[]{});
        } catch (Exception ex) {
            //TODO: log in debug level. Not critical exception
            m = findMethod(clz.getSuperclass(), methodName);
        }
        m.setAccessible(true);
        return m;
    }

    /**Builds select query using fieldNames from bean instance*/
    protected String buildSelectQuery(){
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT ");
        for(String fieldName : fieldNames){
            sb.append(fieldName).append(", ");
        }
        sb.replace(sb.length()-2, sb.length(), "");
        sb.append(" FROM ").append(tableName);

        return sb.toString().toUpperCase();
    }
    
}
